﻿/**	@file		lolix_lock_opt.h
 *	@date		(2013-08-25 23:43:25)/(2013-12-30 01:21:09)
 *-----------------------------------------------------------------------------
 *	@version	1.0.1.2
 *	@author		Nick Shallery	(nicknide@gmail.com)
 *	@copyright	YOU HAVE ALL LEFT WITH THIS CODE WHILE YOU KEEP COMMENT IN EVERY COPY.
 *-----------------------------------------------------------------------------
**/


#if			!defined(__LOLIX_IMP__LOLIX_LOCK_OPT__H__NICK__K_IN_G__)
#define		__LOLIX_IMP__LOLIX_LOCK_OPT__H__NICK__K_IN_G__

#if			!defined(__LOLIX__LOLI_X_CFG__K_IN_G__)
	#include	"../lolix_cfg.h"
#endif	//	!defined(__LOLIX__LOLI_X_CFG__K_IN_G__)

#if			!defined(__LOLIX__LOLI_X_MACRO__K_IN_G__)
	#include	"../lolix_macro.h"
#endif	//	!defined(__LOLIX__LOLI_X_MACRO__K_IN_G__)

#if			!defined(__LOLIX__LOLIX_SUPPORTED__HPP__K_IN_G__)
	#include	"../_lolix_supported.hpp"
#endif	//	!defined(__LOLIX__LOLIX_SUPPORTED__HPP__K_IN_G__)

namespace lolix{namespace imp{
#if			defined(LOLIX_DEF__PLATFORM_TYPE_WINDOWS)
	namespace _help
	{
		extern "C" extern long __cdecl _InterlockedExchangeAdd(long*, long);
		extern "C" extern long __cdecl _InterlockedIncrement(long*);
		extern "C" extern long __cdecl _InterlockedDecrement(long*);
		extern "C" extern long __cdecl _InterlockedExchange(long* ptr, long val);
		extern "C" extern long __cdecl _InterlockedCompareExchange(long* ptr, long val, long cmp);
		//#include	<intrin.h>
		extern "C" extern long LOLIX_CALL _InterlockedOr(long* ptr, long val);
		extern "C" extern long LOLIX_CALL _InterlockedAnd(long* ptr, long val);
		extern "C" extern long LOLIX_CALL _InterlockedXor(long* ptr, long val);
		template<unsigned _Bit = 4>
		struct opt_helper
		{
			template<typename _Ty> static LOLIX_INLINE_CALL _Ty lock_add(_Ty* val, _Ty add){return (_Ty)_InterlockedExchangeAdd((long*)val, (long)add);}
			template<typename _Ty> static LOLIX_INLINE_CALL _Ty lock_sub(_Ty* val, _Ty add){long n = ~(long)add + 1; return (_Ty)_InterlockedExchangeAdd((long*)val, n);}
			template<typename _Ty> static LOLIX_INLINE_CALL _Ty lock_inc(_Ty* val){return (_Ty)_InterlockedIncrement((long*)val);}
			template<typename _Ty> static LOLIX_INLINE_CALL _Ty lock_dec(_Ty* val){return (_Ty)_InterlockedDecrement((long*)val);}
			template<typename _Ty> static LOLIX_INLINE_CALL _Ty lock_chg(_Ty* ptr, _Ty val){return (_Ty)_InterlockedExchange((long*)ptr, (long)val);}
			template<typename _Ty> static LOLIX_INLINE_CALL _Ty lock_cchg(_Ty* ptr, _Ty val, _Ty cmp){return (_Ty)_InterlockedCompareExchange((long*)ptr, (long)val, (long)cmp);}
			template<typename _Ty> static LOLIX_INLINE_CALL _Ty lock_or(_Ty* ptr, _Ty val){return (_Ty)_InterlockedOr((long*)ptr, (long)val);}
			template<typename _Ty> static LOLIX_INLINE_CALL _Ty lock_and(_Ty* ptr, _Ty val){return (_Ty)_InterlockedAnd((long*)ptr, (long)val);}
			template<typename _Ty> static LOLIX_INLINE_CALL _Ty lock_xor(_Ty* ptr, _Ty val){return (_Ty)_InterlockedXor((long*)ptr, (long)val);}
		};
	}

#if		LOLIX_CFG__SIZE_TYPE_BITS_SIZE == 64
	namespace _help
	{
		extern "C" extern long long LOLIX_CALL _InterlockedExchangeAdd64(long long*, long long);
		//extern "C" extern long long LOLIX_CALL InterlockedExchangeSubtract64(long long*, long long);
		extern "C" extern long long LOLIX_CALL _InterlockedIncrement64(long long*);
		extern "C" extern long long LOLIX_CALL _InterlockedDecrement64(long long*);
		extern "C" extern long long __cdecl _InterlockedExchange64(long long* ptr, long long val);
		extern "C" extern long long __cdecl _InterlockedCompareExchange64(long long* ptr, long long val, long long cmp);
		//#include	<intrin.h>
		extern "C" extern long long LOLIX_CALL _InterlockedOr64(long long* ptr, long long val);
		extern "C" extern long long LOLIX_CALL _InterlockedAnd64(long long* ptr, long long val);
		extern "C" extern long long LOLIX_CALL _InterlockedXor64(long long* ptr, long long val);
		template<>
		struct opt_helper<8>
		{
			template<typename _Ty> static LOLIX_INLINE_CALL _Ty lock_add(_Ty* val, _Ty add){return (_Ty)_InterlockedExchangeAdd64((long long*)val, (long long)add);}
			template<typename _Ty> static LOLIX_INLINE_CALL _Ty lock_sub(_Ty* val, _Ty add){long long n = ~(long long)add + 1; return (_Ty)_InterlockedExchangeAdd64((long long*)val, n);}
			template<typename _Ty> static LOLIX_INLINE_CALL _Ty lock_inc(_Ty* val){return (_Ty)_InterlockedIncrement64((long long*)val);}
			template<typename _Ty> static LOLIX_INLINE_CALL _Ty lock_dec(_Ty* val){return (_Ty)_InterlockedDecrement64((long long*)val);}
			template<typename _Ty> static LOLIX_INLINE_CALL _Ty lock_chg(_Ty* ptr, _Ty val){return (_Ty)_InterlockedExchange64((long long*)ptr, (long long)val);}
			template<typename _Ty> static LOLIX_INLINE_CALL _Ty lock_cchg(_Ty* ptr, _Ty val, _Ty cmp){return (_Ty)_InterlockedCompareExchange64((long long*)ptr, (long long)val, (long long)cmp);}
			template<typename _Ty> static LOLIX_INLINE_CALL _Ty lock_or(_Ty* ptr, _Ty val){return (_Ty)_InterlockedOr64((long long*)ptr, (long long*)val);}
			template<typename _Ty> static LOLIX_INLINE_CALL _Ty lock_and(_Ty* ptr, _Ty val){return (_Ty)_InterlockedAnd64((long long*)ptr, (long long*)val);}
			template<typename _Ty> static LOLIX_INLINE_CALL _Ty lock_xor(_Ty* ptr, _Ty val){return (_Ty)_InterlockedXor64((long long*)ptr, (long long*)val);}
		};
	}
#endif	//	LOLIX_CFG__SIZE_TYPE_BITS_SIZE == 64

	template<typename _Ty>	LOLIX_INLINE_CALL _Ty lock_add(_Ty* val, typename lolix::_help::_identity<_Ty>::type add){return _help::opt_helper<sizeof(_Ty)>::lock_add(val, add);}
	template<typename _Ty>	LOLIX_INLINE_CALL _Ty lock_sub(_Ty* val, typename lolix::_help::_identity<_Ty>::type add){return _help::opt_helper<sizeof(_Ty)>::lock_sub(val, add);}
	template<typename _Ty>	LOLIX_INLINE_CALL _Ty lock_inc(_Ty* val){return _help::opt_helper<sizeof(_Ty)>::lock_inc(val);}
	template<typename _Ty>	LOLIX_INLINE_CALL _Ty lock_dec(_Ty* val){return _help::opt_helper<sizeof(_Ty)>::lock_dec(val);}
	template<typename _Ty>	LOLIX_INLINE_CALL _Ty lock_chg(_Ty* ptr, typename lolix::_help::_identity<_Ty>::type val){return _help::opt_helper<sizeof(_Ty)>::lock_chg(ptr, val);}
	template<typename _Ty>	LOLIX_INLINE_CALL _Ty lock_cchg(_Ty* ptr, typename lolix::_help::_identity<_Ty>::type val, typename lolix::_help::_identity<_Ty>::type cmp){return _help::opt_helper<sizeof(_Ty)>::lock_cchg(ptr, val, cmp);}
	template<typename _Ty>	LOLIX_INLINE_CALL _Ty lock_or(_Ty* ptr, typename lolix::_help::_identity<_Ty>::type val){return _help::opt_helper<sizeof(_Ty)>::lock_or(ptr, val);}
	template<typename _Ty>	LOLIX_INLINE_CALL _Ty lock_and(_Ty* ptr, typename lolix::_help::_identity<_Ty>::type val){return _help::opt_helper<sizeof(_Ty)>::lock_and(ptr, val);}
	template<typename _Ty>	LOLIX_INLINE_CALL _Ty lock_xor(_Ty* ptr, typename lolix::_help::_identity<_Ty>::type val){return _help::opt_helper<sizeof(_Ty)>::lock_xor(ptr, val);}
#else	//	defined(LOLIX_DEF__PLATFORM_TYPE_WINDOWS)

	template<typename _Ty>	LOLIX_INLINE_CALL _Ty lock_add(_Ty* val, typename lolix::_help::_identity<_Ty>::type add){return __sync_add_and_fetch(val, add);}
	template<typename _Ty>	LOLIX_INLINE_CALL _Ty lock_sub(_Ty* val, typename lolix::_help::_identity<_Ty>::type add){return __sync_sub_and_fetch(val, add);}
	template<typename _Ty>	LOLIX_INLINE_CALL _Ty lock_inc(_Ty* val){return __sync_add_and_fetch(val, 1);}
	template<typename _Ty>	LOLIX_INLINE_CALL _Ty lock_dec(_Ty* val){return __sync_sub_and_fetch(val, 1);}
	template<typename _Ty>	LOLIX_INLINE_CALL _Ty lock_chg(_Ty* ptr, typename lolix::_help::_identity<_Ty>::type val){return __sync_lock_test_and_set(ptr, val);}
	template<typename _Ty>	LOLIX_INLINE_CALL _Ty lock_cchg(_Ty* ptr, typename lolix::_help::_identity<_Ty>::type val, _Ty cmp){return __sync_val_compare_and_swap(ptr, val, cmp);}
	template<typename _Ty>	LOLIX_INLINE_CALL _Ty lock_or(_Ty* ptr, typename lolix::_help::_identity<_Ty>::type val){return __sync_or_and_fetch(ptr, val);}
	template<typename _Ty>	LOLIX_INLINE_CALL _Ty lock_and(_Ty* ptr, typename lolix::_help::_identity<_Ty>::type val){return __sync_and_and_fetch(ptr, val);}
	template<typename _Ty>	LOLIX_INLINE_CALL _Ty lock_xor(_Ty* ptr, typename lolix::_help::_identity<_Ty>::type val){return __sync_xor_and_fetch(ptr, val);}

#endif	//	defined(LOLIX_DEF__PLATFORM_TYPE_WINDOWS)
}}

#endif	//	!defined(__LOLIX_IMP__LOLIX_LOCK_OPT__H__NICK__K_IN_G__)
